﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cos.Core.Exception;
using Cos.Core.Model.Common;
using Cos.Core.Model.Content;
using Cos.Core.Model.Template;
using Cos.Core.Service;
using Cos.Module.CMS.Data;
using Cos.Module.Configuration;
using Cos.Module.Membership;
using Cos.Module.Template;
using Microsoft.Practices.Unity;

namespace Cos.Module.CMS
{
    public class PageService : ServiceBase, IPageService
    {
        private readonly ICultureService cultureService;
        private readonly INavRepository navRepository;
        private readonly IPageRepository pageRepository;
        private readonly IElementRepository elementRepository;
        private readonly ISiteService siteService;
        private readonly IMembershipService membershipService;
        private readonly ITemplateService templateService;

        [InjectionConstructor]
        public PageService(ICultureService cultureService, INavRepository navRepository, IPageRepository pageRepository, IElementRepository elementRepository, ISiteService siteService, IMembershipService membershipService, ITemplateService templateService)
        {
            this.cultureService = cultureService;
            this.navRepository = navRepository;
            this.pageRepository = pageRepository;
            this.elementRepository = elementRepository;
            this.siteService = siteService;
            this.membershipService = membershipService;
            this.templateService = templateService;
        }

        public Nav GetNav(int navId)
        {
            return this.navRepository.GetNav(navId);
        }

        /// <summary>
        /// Get the page from page id.
        /// </summary>
        /// <typeparam name="T">The model class</typeparam>
        /// <param name="pageId">Id of the page.</param>
        /// <param name="isLiveMode">if set to <c>true</c> [viewing the site in live mode].</param>
        /// <returns>
        /// a content page
        /// </returns>
        /// <exception cref="PageNotFoundException">If the page is not found</exception>
        public Page GetPage(int pageId)
        {
            return this.pageRepository.GetPage(pageId);
        }

        public Page GetPage(Culture cultureVo, int navId)
        {
            return this.pageRepository.GetPage(cultureVo.CultureCode, navId);
        }
        
        public IEnumerable<Page> GetSubPages(int pageId)
        {
            return this.pageRepository.GetSubPages(pageId);
        }

        public IEnumerable<Page> GetSubPages(Culture cultureVo, int navId)
        {
            return this.pageRepository.GetSubPages(cultureVo.CultureCode, navId);
        }
        
        public IEnumerable<Page> GetPages(Culture cultureVo)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<Page> GetPages(Culture cultureVo, string multiAssociationNavIds)
        {
            throw new NotImplementedException();
        }

        public Page GetFirstTemplatePage(string templateName, Culture cultureVo)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<Page> GetTemplatePages(string templateName, Culture culture)
        {
            return this.pageRepository.GetTemplatePages(templateName, culture.CultureCode);
        }
        
        public Page SavePage(Nav nav, Page page,  IEnumerable<Element> elements)
        {
            // If new
            if (page.PageId == 0 && nav.ParentNavId.HasValue && nav.TemplateId.HasValue)
            {
                var parentId = nav.ParentNavId.Value;
                var templateId = nav.TemplateId.Value;
                nav = this.CreateNav(parentId, templateId);

                // Create Pages (1 per culture)
                var cultures = this.cultureService.GetCultures();

                foreach (var c in cultures)
                {
                    var p = this.CreatePage(c, nav, page);

                    // Create pages Elements (based on the template)
                    var parts = this.templateService.GetParts(templateId);

                    foreach (var part in parts)
                    {
                        this.CreateElement(part, p);
                    }
                }

                return this.pageRepository.GetPage(page.CultureCode, nav.NavId);
            }
            
            // Save the page information
            page = this.pageRepository.SavePage(page);

            // Save the page elements
            this.SaveElements(page.PageId, elements);

            return page;
        }

        public IEnumerable<Element> SaveElements(int pageId, IEnumerable<Element> elements)
        {
            var pageElements = this.GetElements(pageId);

            foreach (var element in elements)
            {
                var partId = element.PartId;
                var ele = pageElements.Where(e => e.PartId == partId).First();

                element.ElementId = ele.ElementId;
                element.PageId = ele.PageId;

                this.SaveElement(element);
            }

            return elements;
        }

        protected Nav CreateNav(int parentNavId, int templateId)
        {
            var nav = new Nav
            {
                InheritPermissions = true,
                NavOrder = this.navRepository.NextNavOrder(parentNavId),
                ParentNavId = parentNavId,
                TemplateId = templateId
            };

            // Create Nav
            return this.navRepository.SaveNav(nav);
        }

        protected Page CreatePage(Culture culture, Nav nav, Page page)
        {
            var p = new Page
            {
                ApprobationDate = page.ApprobationDate,
                Author = page.Author,
                CreationDate = page.CreationDate,
                CultureCode = culture.CultureCode,
                LastModified = page.LastModified,
                NavId = nav.NavId,
                PageName = page.PageName,
                PageNamePreview = page.PageNamePreview,
                PageNavEnd = page.PageNavEnd,
                PageStatus = page.PageStatus,
                PageVisibility = page.PageVisibility,
                PageVisibilityPreview = page.PageVisibilityPreview
            };

            return this.pageRepository.SavePage(p);
        }

        protected Element CreateElement(Part part, Page page)
        {
            var element = new Element
            {
                PartId = part.Id,
                PageId = page.PageId
            };

            return this.elementRepository.SaveElement(element);
        }

        public Element GetElement(Culture culture, int navId, string partName)
        {
            var nav = this.navRepository.GetNav(navId);

            if (!nav.TemplateId.HasValue)
            {
                return null;
            }

            var part = this.templateService.GetPart(nav.TemplateId.Value, partName);

            if (part == null)
            {
                return null;
            }

            int partId = part.Id;

            return this.elementRepository.GetElement(culture.CultureCode, navId, partId);
        }

        public IEnumerable<Element> GetElements(int pageId)
        {
            return this.elementRepository.GetElements(pageId);
        }

        public Element SaveElement(Element element)
        {
            return this.elementRepository.SaveElement(element);
        }
    }
}
